package com.simple.mybaits.simplemybatis;

import com.simple.mybaits.simplemybatis.annotation.*;
import com.simple.mybaits.simplemybatis.comandEnum.SqlCommand;
import com.simple.mybaits.simplemybatis.proxy.MapperProxy;
import com.simple.mybaits.simplemybatis.statement.MapperStatement;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;

/**
 * @author : zxj
 * @package :  com.simple.mybaits.simplemybatis
 * @date :  2018/5/21
 * @description : mybatis配置中心
 */
public class Configuration {
    /**
     * 配置
     */
    private static final String DEFAULT_CONFIG_LOCATION = "application.properties";

    /**
     * mapper扫描的包路径
     */
    public static final String MAPPER_SCAN_BASEPACKAGE = "mapper.scan.basepackage";

    /**
     * Mapper的注册
     */
    private Map<Class<?>, MapperProxy> mapperProxyRegister = new HashMap<>();

    /**
     * mapperClass
     */
    private List<Class<?>> mapperClass = new ArrayList<>();

    /**
     * mapperStatement的注册
     */
    private Map<String, MapperStatement> mapperStatementRegister = new HashMap<>();

    /**
     * 加载配置服务
     */
    public Properties load() {
        Properties config = new Properties();
        try {
            config.load(Configuration.class.getClassLoader().getResourceAsStream(DEFAULT_CONFIG_LOCATION));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return config;
    }

    public String getKey(String key) {
        Properties properties = load();

        if (properties.containsKey(key)) {
            return properties.getProperty(key);
        } else {
            return "";
        }
    }

    public Map<Class<?>, MapperProxy> getMapperProxyRegister() {
        return mapperProxyRegister;
    }

    public void setMapperProxyRegister(Map<Class<?>, MapperProxy> mapperProxyRegister) {
        this.mapperProxyRegister = mapperProxyRegister;
    }

    public Map<String, MapperStatement> getMapperStatementRegister() {
        return mapperStatementRegister;
    }

    public void setMapperStatementRegister(Map<String, MapperStatement> mapperStatementRegister) {
        this.mapperStatementRegister = mapperStatementRegister;
    }

    /**
     * 扫描mapper类
     */
    public List<Class<?>> doScanMapper(String packageName) {

        addClass(Thread.currentThread().getContextClassLoader(), packageName, mapperClass);
        /**
         * 扫描包
         */
        for (Class<?> clazz : mapperClass) {
            if (!mapperProxyRegister.containsKey(clazz)) {
                mapperProxyRegister.put(clazz, new MapperProxy());
            }
        }
        return mapperClass;
    }

    public void registerMapperStatement() {
        //注册MapperStatement
        for (Class<?> clazz : mapperClass) {
            Method[] methods = clazz.getDeclaredMethods();

            //循环遍历每一个属性
            for (Method method : methods) {
                MapperStatement mapperStatement = new MapperStatement();
                String mapperId = clazz.getName() + "." + method.getName();
                mapperStatement.setMapperId(mapperId);

                String sql = "";
                if (method.isAnnotationPresent(Select.class)) {
                    sql = method.getAnnotation(Select.class).value();
                    mapperStatement.setSqlCommand(SqlCommand.SELECT);
                } else if (method.isAnnotationPresent(Update.class)) {
                    sql = method.getAnnotation(Update.class).value();
                    mapperStatement.setSqlCommand(SqlCommand.UPDATE);
                }else if (method.isAnnotationPresent(Insert.class)) {
                    sql = method.getAnnotation(Insert.class).value();
                    mapperStatement.setSqlCommand(SqlCommand.INSERT);
                }else if (method.isAnnotationPresent(Delete.class)) {
                    sql = method.getAnnotation(Delete.class).value();
                    mapperStatement.setSqlCommand(SqlCommand.DELETE);
                } else {
                    throw new RuntimeException("no annotaion found");
                }
                mapperStatement.setBoundSql(sql);
                mapperStatement.setParams(method.getParameterTypes());
                mapperStatement.setResult(method.getReturnType());
                mapperStatement.setMethod(method);

                if (!mapperStatementRegister.containsKey(mapperId)) {
                    mapperStatementRegister.put(mapperId, mapperStatement);
                }
            }
        }

    }

    /**
     * 获取包下所有实现了superStrategy的类并加入list
     */
    private static void addClass(ClassLoader classLoader, String packagePath, List<Class<?>> classes) {
        URL url = classLoader.getResource(packagePath.replace(".", "/"));
        String protocal = url.getProtocol();

        if ("file".equals(protocal)) {
            // 本地自己可见的代码
            findMapperAnnotationClass(classLoader, packagePath, classes);
        }
    }

    /**
     * 寻找classs
     */
    public static void findMapperAnnotationClass(ClassLoader classLoader, String packageName, List<Class<?>> classes) {
        URI url = null;
        try {
            url = classLoader.getResource(packageName.replace(".", "/")).toURI();
        } catch (URISyntaxException e) {
            throw new RuntimeException("未找到策略资源");
        }
        File file = new File(url);

        file.listFiles(new FileFilter() {
            @Override
            public boolean accept(File file) {
                if (file.isDirectory()) {
                    findMapperAnnotationClass(classLoader, packageName + "." + file.getName(), classes);
                } else if (file.getName().endsWith(".class")) {
                    try {
                        System.out.println(packageName + "." + file.getName().replace(".class", ""));
                        Class clazz = classLoader.loadClass(packageName + "." + file.getName().replace(".class", ""));
                        if (clazz.isAnnotationPresent(Mapper.class)) {
                            classes.add(clazz);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                    return true;
                }
                return false;
            }
        });
    }

//    public static void main(String[] args) {
//        List<Class<?>> classes = new ArrayList<>();
//        addClass(Thread.currentThread().getContextClassLoader(), "com.simple.mybaits.simplemybatis.mapper", classes);
//        System.out.println(classes);
//    }

}

